package com.privatetime.dao.impl;

import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.sql.SQLException;
import java.util.List;

import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.privatetime.common.Pagination;
import com.privatetime.dao.BaseDao;

public abstract class BaseDaoImpl<E, PK extends Serializable> extends
		HibernateDaoSupport implements BaseDao<E, PK> {

	protected final Logger logger = Logger.getLogger(getClass());

	private Class<E> clazz;

	@SuppressWarnings("unchecked")
	public BaseDaoImpl() {
		clazz = (Class<E>) ((ParameterizedType) getClass()
				.getGenericSuperclass()).getActualTypeArguments()[0];
	}

	@SuppressWarnings("unchecked")
	public PK createEntity(E entity) {
		try {
			return (PK) getHibernateTemplate().save(entity);
		} catch (Exception e) {
			logger.info("BaseDaoImpl - createEntity - Exception:"
					+ e.getMessage());
		}
		return null;
	}

	public void deleteEntity(E entity) {
		try {
			getHibernateTemplate().delete(entity);
		} catch (Exception e) {
			logger.info("BaseDaoImpl - deleteEntity - Exception:"
					+ e.getMessage());
		}
	}

	public void deleteEntityById(PK id) {
		deleteEntity(retrieveEntity(id));
	}

	@SuppressWarnings("unchecked")
	public E retrieveEntity(PK id) {
		try {
			return (E) getHibernateTemplate().get(clazz, id);
		} catch (Exception e) {
			logger.info("BaseDaoImpl - retrieveEntity - Exception:"
					+ e.getMessage());
		}
		return null;
	}

	public void updateEntity(E entity) {
		try {
			getHibernateTemplate().saveOrUpdate(entity);
		} catch (Exception e) {
			logger.info("BaseDaoImpl - updateEntity - Exception:"
					+ e.getMessage());
		}
	}

	public List<E> findEntityList(final String sql,
			final Pagination<E> pagination) {
		return findEntityList(sql, pagination, null);
	}

	@SuppressWarnings("unchecked")
	public List<E> findEntityList(final String sql,
			final Pagination<E> pagination, final Object... parameters) {
		List<E> entityList = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(sql);
						if (pagination != null) {
							int first = (pagination.getPageSize() * (pagination
									.getCurrentIndex() - 1)) + 1;
							query.setFirstResult(first);
							query.setMaxResults(pagination.getPageSize());
						}
						for (int i = 0; i < parameters.length; i++) {
							query.setParameter(i, parameters[i]);
						}
						return query.list();
					}
				});
		return entityList;
	}

	public List<E> findEntityList(final String sql, final Object... parameters) {
		return findEntityList(sql, null, parameters);
	}

	public E findEntityUnique(final String sql) {
		return findEntityUnique(sql, null);
	}

	@SuppressWarnings("unchecked")
	public E findEntityUnique(final String sql, final Object... parameters) {
		E entityUnique = (E) getHibernateTemplate().execute(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(sql);
						for (int i = 0; i < parameters.length; i++) {
							query.setParameter(i, parameters[i]);
						}
						return query.uniqueResult();

					}
				});
		return entityUnique;
	}

	@SuppressWarnings("unchecked")
	public List<E> findEntityList(final String sql, final String flag,
			final List parameters) {
		List<E> entityList = getHibernateTemplate().executeFind(
				new HibernateCallback() {
					public Object doInHibernate(Session session)
							throws HibernateException, SQLException {
						Query query = session.createQuery(sql);
						query.setParameterList(flag, parameters);
						return query.list();
					}
				});
		return entityList;
	}

	public List<E> findEntityAll() {
		StringBuffer sql = new StringBuffer();
		sql.append("from ").append(clazz.getName());
		return findEntityList(sql.toString());
	}
}
